#include "SDL.h"
#include "SDL_image.h"
#ifdef USE_SDL_GFX
#include "SDL_gfxPrimitives.h"
#endif
#include "sprite_contour.h"
#include <string.h>
#include <time.h>
#include <iostream>
using namespace std;
using namespace SpriteContourExtractor;


#define SCREEN_W	(800)
#define SCREEN_H  (600)

static SDL_Surface* screen = NULL;
static SDL_Surface* sprite = NULL;
static list<Point2d*> contour;

static void free_contour () {
	return;
	for (list<Point2d*>::iterator it = contour.begin();
			 it != contour.end();
			 it++) {
		delete *it;
	}
	contour.clear();
}

static void wait_keypress () {
	SDL_Event evt;
	cout << "*** PRESS ANY KEY ***" << endl;
	for (;;) {
		SDL_WaitEvent(&evt);
		if (evt.type == SDL_KEYDOWN) {
			break;
		}
	}
}

static void blit_sprite_and_contour () {
	SDL_Rect src, dst;
	SDL_Event evt;

	// Prepare blit sprite (screen centered)
	src.x = 0;
	src.y = 0;
	src.w = sprite->w;
	src.h = sprite->h;

	dst.x = ((SCREEN_W - sprite->w) >> 1) + 50;
	dst.y = ((SCREEN_H - sprite->h) >> 1) + 20;
	dst.w = src.w;
	dst.h = src.h;

	Sint16 offx = dst.x;
	Sint16 offy = dst.y;

	// Blit sprite and contour (sprite screen coordinate translated)
  SDL_BlitSurface(sprite, &src, screen, &dst);
	SDL_Surface* new_surf = SDL_DisplayFormat(sprite);
	SDL_FillRect(new_surf,NULL,SDL_MapRGB(screen->format,200,100,50));
	dst.x = 0;
	dst.y = 0;
	SDL_BlitSurface(sprite, &src, new_surf, &dst);

  Point2d* first_pt = NULL;
	Point2d* prev_pt = NULL;
  Point2d* pt = NULL;
	Uint32 cyan = SDL_MapRGB(screen->format,0,255,255);

	for (list<Point2d*>::iterator it = contour.begin();
			 it != contour.end();
			 it++) {
		pt = *it;
#if defined(USE_SDL_GFX)
    if (first_pt == NULL) {
      first_pt = pt;
    }
    if (prev_pt != NULL) {
			aalineRGBA(
				screen,
				prev_pt->x+offx,prev_pt->y+offy,pt->x+offx,pt->y+offy,
				0,255,255,255
			);
      circleRGBA(
        screen,
        prev_pt->x+offx,prev_pt->y+offy,1,
        255,255,0,255
      );
			aalineRGBA(
				new_surf,
				prev_pt->x+offx,prev_pt->y+offy,pt->x+offx,pt->y+offy,
				0,255,255,255
			);
      pixelRGBA(
        new_surf,
        pt->x+offx,pt->y+offy,
        255,255,0,255
      );
			SDL_UpdateRect(screen,0,0,SCREEN_W,SCREEN_H);
		}
		prev_pt = pt;
#else
		dst.x = pt->x + offx;
		dst.y = pt->y + offy;
		dst.w = 1;
		dst.h = 1;
		SDL_FillRect(screen,&dst,cyan);
		SDL_UpdateRects(screen,1,&dst);
		dst.x = pt->x;
		dst.y = pt->y;
		SDL_FillRect(new_surf,&dst,cyan);
#endif

		while (SDL_PollEvent(&evt) > 0) {
			if (evt.type == SDL_KEYDOWN) {
				SDL_FreeSurface(new_surf);
				return;
			}
		}
		SDL_Delay(5);
	}
  // Join the last and first points
#if defined(USE_SDL_GFX)
  aalineRGBA(
      screen,
      pt->x+offx,pt->y+offy,first_pt->x+offx,first_pt->y+offy,
      0,255,255,255
      );
  aalineRGBA(
      new_surf,
      pt->x+offx,pt->y+offy,first_pt->x+offx,first_pt->y+offy,
      0,255,255,255
      );
  SDL_UpdateRect(screen,0,0,SCREEN_W,SCREEN_H);
#endif
  cout << "*** INFO: saving sprite with contour." << endl;
	SDL_SaveBMP(new_surf, "sprite_with_contour.bmp");
	SDL_FreeSurface(new_surf);
}

int main (int argc, char** argv) {
	if (argc < 3) {
		cerr << "*** ERROR: Syntax is:" << endl;
		cerr << argv[0] << " [sprite image file] [orientation]" << endl;
		cerr << " where:" << endl;
		cerr << "   orientation is an integer, 1 for 'clockwise'," << endl;
		cerr << "               any other integer for counter clockwise." << endl;
		return EXIT_FAILURE;
	}
	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
		cerr << "*** ERROR: Coudln't initialize SDL." << endl;
		return EXIT_FAILURE;
	}
	atexit(SDL_Quit);
	if ((screen =
        SDL_SetVideoMode(SCREEN_W,SCREEN_H,0,SDL_ANYFORMAT|SDL_FULLSCREEN))
			== NULL) {
		cerr << "*** ERROR: Couldn't setup a " << SCREEN_W << "x" << SCREEN_H
				 << " display." << endl;
		return EXIT_FAILURE;
	}
	if ((sprite = IMG_Load(argv[1])) == NULL) {
		cerr << "*** ERROR: Couldn't load sprite image file: " << argv[1] << endl;
		return EXIT_FAILURE;
	}

	bool orientation = (atoi(argv[2]) == 1) ? (true) : (false);

  SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format,50,50,50));

  stringRGBA(screen,10,10,"Polygonal Sprite Contour, (c) 2010 by Andematunum",
              255,255,255,255
  );
  stringRGBA(screen,10,30,"Suggestions, bug reports: andematunum@gmail.com",
              255,255,255,255
  );

	if (orientation) {
		cout << "*** INFO: Clockwise contour." << endl;
    stringRGBA(screen,10,50,"CLOCKWISE",255,255,0,255);
	}
	else {
  	cout << "*** INFO: Counter clockwise contour." << endl;
    stringRGBA(screen,10,50,"COUNTER CLOCKWISE",255,255,0,255);
	}

  time_t start;
  time(&start);
	extract_contour(
		sprite->pixels,
		Point2d(sprite->w,sprite->h),
		sprite->format->BitsPerPixel,
		sprite->format->colorkey,
		orientation,
		contour
	);
  time_t end;
  time(&end);
  double elapsed = difftime(end,start);
  char msg[64];
  sprintf(&msg[0], "%zi points extracted in %d seconds.",
          contour.size(), (int)elapsed);
  stringRGBA(screen,10,70,&msg[0],255,255,0,255);
  stringRGBA(screen,10,100,"Press any key to interrupt",255,255,0,255);

	cout << "*** INFO: Extracted, " << contour.size() << " points." << endl;
	blit_sprite_and_contour();
  stringRGBA(screen,10,130,"Press any key to QUIT",255,0,0,255);
  SDL_UpdateRect(screen,0,0,SCREEN_W,SCREEN_H);
	wait_keypress();
	free_contour();

	SDL_FreeSurface(sprite);

	return EXIT_SUCCESS;
}

